package com.clei.netty.file.client;

import com.clei.consts.NettyConstants;
import com.clei.netty.file.enums.FileCmdTypeEnum;
import com.clei.netty.util.FileDataManager;
import com.clei.netty.util.FilePathManager;
import com.clei.utils.ByteUtil;
import com.clei.utils.PrintUtil;
import com.clei.utils.StringUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.function.Consumer;

/**
 * file client
 * 可以上传和获取文件的client
 *
 * @author Y
 * @date 2022-04-21
 */
public class FileClient {

    /**
     * 输入命令分隔符
     */
    private static final String SEPARATOR = "  ";

    /**
     * 文件存储路径
     */
    private static String fileDirectory = "";

    public static void main(String[] args) {
        PrintUtil.log("File Client 启动");
        // 启动
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        try {
            MsgSender msgSender = new MsgSender();
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(bossGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new FileClientInitializer(msgSender));
            // 连接
            Channel channel = bootstrap.connect(NettyConstants.SERVER_IP, NettyConstants.SERVER_PORT).sync().channel();
            msgSender.setChannel(channel);
            // 输入并发送
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            String exitMsg = "EXIT";
            String msg = in.readLine();
            while (!exitMsg.equals(msg)) {
                handleMsg(msgSender, msg);
                msg = in.readLine();
            }
        } catch (Exception e) {
            PrintUtil.log(e);
        } finally {
            bossGroup.shutdownGracefully();
        }
    }

    /**
     * 输入消息处理
     *
     * @param msgSender 消息发送者
     * @param msg       输入消息
     */
    private static void handleMsg(MsgSender msgSender, String msg) {
        String[] arr = msg.split(SEPARATOR);
        String cmd = arr[0];
        FileCmdTypeEnum cmdType = FileCmdTypeEnum.getByName(cmd);
        if (null == cmdType) {
            PrintUtil.log("未知命令！");
            return;
        }
        switch (cmdType) {
            case CONF_FILE_DIRECTORY:
                String tempDirectory = arr[1];
                File tempFile = new File(tempDirectory);
                tempFile.mkdirs();
                fileDirectory = arr[1];
                PrintUtil.log("设置文件存储路径成功 : {}", fileDirectory);
                break;
            // 文件上传
            case REQ_UPLOAD:
                String filePath = arr[1];
                File file = new File(filePath);
                if (!file.exists() || file.isDirectory()) {
                    PrintUtil.log("文件不存在或类型错误！ filePath : {}", filePath);
                } else {
                    String fileName = file.getName();
                    long fileSize = file.length();
                    FilePathManager.put(fileName, filePath);
                    // 文件大小 文件名
                    byte[] data = ByteUtil.merge(ByteUtil.longTo8Byte(fileSize), ByteUtil.toBytes(fileName));
                    msgSender.sendMsg(cmdType.getCmdCode(), data);
                }
                break;
            case REQ_CATEGORY:
            case REQ_CAPTURE_SCREEN:
                msgSender.sendMsg(cmdType.getCmdCode());
                break;
            case REQ_CMD:
                String cmdContent = arr[1];
                msgSender.sendMsg(cmdType.getCmdCode(), ByteUtil.toBytes(cmdContent));
            case REQ_DOWNLOAD:
                if (StringUtil.isBlank(fileDirectory)) {
                    PrintUtil.log("未设置文件存储路径");
                    return;
                }
                String fileName = arr[1];
                // fileId 接收数据的时候作为标识
                int fileId = fileName.hashCode();
                Long fileSize = FileClientHandler.FILE_NAME_SIZE.get(fileName);
                if (null == fileSize) {
                    PrintUtil.log("未获取到文件大小");
                } else {
                    int capacity = (int) ((fileSize + NettyConstants.FILE_BUFFER_SIZE - 1) / NettyConstants.FILE_BUFFER_SIZE);
                    // 文件传输完毕的操作
                    Consumer<Integer> callbackHandler = f -> PrintUtil.log("{}下载成功");
                    FileDataManager.put(fileId, capacity, fileDirectory + File.separator + fileName, false, callbackHandler);
                    msgSender.sendMsg(cmdType.getCmdCode(),
                            ByteUtil.merge(ByteUtil.intTo4Byte(fileId), ByteUtil.toBytes(fileName)));
                }
                break;
            case HELP:
                Arrays.stream(FileCmdTypeEnum.values())
                        .filter(c -> !c.name().startsWith("RES"))
                        .forEach(c -> PrintUtil.log("{}  {}", c.name(), c.getCmdName()));
                break;
            default:
        }
    }
}
